package com.geek.utils;

import com.geek.base.file.bean.FileBean;
import com.geek.base.file.bean.SftpBean;
import com.jcraft.jsch.*;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;

public class SftpPoolUtil {


    /**
     * sftp连接池
     */
    private static final Map<String, Channel> SFTP_CHANNEL_POOL = new HashMap<String, Channel>();

    /**
     * 打开sftp协议连接
     */
    public static ChannelSftp openSftpConnect(SftpBean sftpBean) throws JSchException {
        Session sshSession = null;
        Channel channel = null;
        ChannelSftp sftp = null;
        String userName = sftpBean.getUserName();
        String passWord = sftpBean.getPassWord();
        String host = sftpBean.getHost();
        int port = sftpBean.getPort();
        String privateKey = sftpBean.getPrivateKey();
        StringBuffer keyBuf = new StringBuffer();
        keyBuf.append(host);
        keyBuf.append(",");
        keyBuf.append(port);
        keyBuf.append(",");
        keyBuf.append(userName);
        keyBuf.append(",");
        keyBuf.append(passWord);
        String key = keyBuf.toString();
        if (null == SFTP_CHANNEL_POOL.get(key)) {
            JSch jsch = new JSch();
            jsch.getSession(userName, host, port);
            sshSession = jsch.getSession(userName, host, port);
            if (!StringUtils.isEmpty(passWord)) {
                sshSession.setPassword(passWord);
            }
            if (StringUtils.isEmpty(privateKey)) {
                jsch.addIdentity(privateKey);
            }
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            channel = sshSession.openChannel("sftp");
            channel.connect();
            SFTP_CHANNEL_POOL.put(key, channel);
        } else {
            channel = SFTP_CHANNEL_POOL.get(key);
            sshSession = channel.getSession();
            if (!sshSession.isConnected()) {
                sshSession.connect();
            }
            if (!channel.isConnected()) {
                channel.connect();
            }
        }
        sftp = (ChannelSftp) channel;
        return sftp;
    }


    /**
     * 关闭协议(关闭会导致连接池异常，因此不建议用户自定义关闭)
     */
    private static void closeSftpConnect(final ChannelSftp sftp) throws Exception {
        if (sftp != null) {
            Session session = sftp.getSession();
            if (session != null) {
                if (session.isConnected()) {
                    session.disconnect();
                }
            }
            if (sftp.isConnected()) {
                sftp.disconnect();
            }
        }
    }


    /**
     * 下载文件
     */
    public static File downloadFile(final String remoteFile, final String localFile, final ChannelSftp sftp)
            throws Exception {
        FileOutputStream os = null;
        File file = new File(localFile);
        try {
            if (!file.exists()) {
                File parentFile = file.getParentFile();
                if (!parentFile.exists()) {
                    parentFile.mkdirs();
                }
                file.createNewFile();
            }
            os = new FileOutputStream(file);
            List<String> list = formatPath(remoteFile);
            sftp.get(list.get(0) + list.get(1), os);
        } catch (Exception e) {
            throw e;
        } finally {
            os.close();
        }
        return file;
    }

    /**
     * 下载文件
     */
    public static byte[] downloadFileToByte(final String remoteFile, final ChannelSftp sftp) throws Exception {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            List<String> list = formatPath(remoteFile);
            sftp.get(list.get(0) + list.get(1), os);
        } catch (Exception e) {
            throw e;
        } finally {
            os.close();
        }
        return os.toByteArray();
    }

    /**
     * 删除文件
     */
    public static void rmFile(final String filePath, final ChannelSftp sftp) throws SftpException {
        List<String> list = formatPath(filePath);
        String dir = list.get(0);
        String file = list.get(1);
        if (isExistDir(dir + file, sftp)) {
            sftp.rm(list.get(0) + list.get(1));
        }
    }

    /**
     * 删除文件夹
     */
    public static void rmDir(final String filePath, final ChannelSftp sftp, final boolean isAll)
            throws SftpException {
        String formatPath = formatPath(filePath).get(0);
        if (isExistDir(formatPath, sftp)) {
            if (isAll) {
                //递归删除
                rmDirAll(formatPath, sftp);
            } else {
                sftp.rmdir(formatPath);
            }
        }
    }

    /**
     * 递归删除执行
     */
    private static void rmDirAll(final String pathString, final ChannelSftp sftp) throws SftpException {
        Vector<ChannelSftp.LsEntry> vector = sftp.ls(pathString);
        if (vector.size() == 1) {
            // 文件，直接删除
            sftp.rm(pathString);
        } else if (vector.size() == 2) {
            // 空文件夹，直接删除
            sftp.rmdir(pathString);
        } else {
            String fileName = "";
            // 删除文件夹下所有文件
            for (ChannelSftp.LsEntry en : vector) {
                fileName = en.getFilename();
                if (".".equals(fileName) || "..".equals(fileName)) {
                    continue;
                } else {
                    rmDirAll(pathString + "/" + fileName, sftp);
                }
            }
            // 删除文件夹
            sftp.rmdir(pathString);
        }
    }

    /**
     * 上传文件
     */
    private static void uploadFile(final String localFile, final String filePath, final String fileName, final ChannelSftp sftp)
            throws SftpException {
        if (isExistDir(filePath, sftp)) {
            mkDir(filePath, sftp);
        }
        sftp.cd(filePath);
        sftp.put(localFile, fileName);
    }

    /**
     * 上传文件
     */
    public static boolean uploadFile(final String localFile, final ChannelSftp sftp) throws SftpException {
        File file = new File(localFile);
        if (file.exists()) {
            List<String> list = formatPath(localFile);
            uploadFile(localFile, list.get(0), list.get(1), sftp);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 根据路径创建文件夹
     */
    public static boolean mkDir(final String filePath, final ChannelSftp sftp) throws SftpException {
        if (StringUtils.isEmpty(filePath))
            return false;
        String md = filePath.replaceAll("\\\\", "/");
        if (md.indexOf("/") != 0 || md.length() == 1) {
            return false;
        } else {
            return mkDirs(md, sftp);
        }
    }

    /**
     * 递归创建文件夹
     */
    private static boolean mkDirs(final String filePath, final ChannelSftp sftp) throws SftpException {
        String dirs = filePath.substring(1, filePath.length() - 1);
        String[] dirArr = dirs.split("/");
        String base = "";
        for (String d : dirArr) {
            base += "/" + d;
            if (isExistDir(base + "/", sftp)) {
                continue;
            } else {
                sftp.mkdir(base + "/");
            }
        }
        return true;
    }

    /**
     * 判断文件夹是否存在
     */
    private static boolean isExistDir(final String filePath, final ChannelSftp sftp) {
        try {
            Vector<?> vector = sftp.ls(filePath);
            if (null == vector) {
                return false;
            } else {
                return true;
            }
        } catch (SftpException e) {
            return false;
        }
    }

    /**
     * 列出目录下的文件
     */
    public static List<ChannelSftp.LsEntry> listFile(String filePath, final ChannelSftp sftp) {
        try {
            List<ChannelSftp.LsEntry> fileList = sftp.ls(filePath);
            return fileList;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Linux文件系统信息转换
     */
    public static List<FileBean> getWebFileList(List<ChannelSftp.LsEntry> lsFileList) {
        List<FileBean> fileList = null;
        if (null != lsFileList) {
            fileList = new ArrayList<FileBean>();
            for (ChannelSftp.LsEntry lsEntry : lsFileList) {
                SftpATTRS attrs = lsEntry.getAttrs();
                if (".".equals(lsEntry.getFilename()) || "..".equals(lsEntry.getFilename())) {

                } else {
                    FileBean fileBean = new FileBean();
                    fileBean.setFileName(lsEntry.getFilename());
                    fileBean.setFileSize(attrs.getSize());
                    fileBean.setFileType(attrs.isDir());
                    Integer atime = attrs.getATime();
                    Integer mtime = attrs.getMTime();
                    fileBean.setAccessTime(DateUtil.timeStampToDate(atime.longValue(), DateUtil.DATE_STR_FULL));
                    fileBean.setModifyTime(DateUtil.timeStampToDate(mtime.longValue(), DateUtil.DATE_STR_FULL));
                    fileList.add(fileBean);
                }
            }
        }
        return fileList;
    }


    /**
     * 格式化路径
     */
    public static List<String> formatPath(final String srcPath) {
        List<String> list = new ArrayList<String>(2);
        String repSrc = srcPath.replaceAll("\\\\", "/");
        int firstP = repSrc.indexOf("/");
        int lastP = repSrc.lastIndexOf("/");
        String fileName = lastP + 1 == repSrc.length() ? "" : repSrc.substring(lastP + 1);
        String dir = firstP == -1 ? "" : repSrc.substring(firstP, lastP);
        dir = (dir.length() == 1 ? dir : (dir + "/"));
        list.add(dir);
        list.add(fileName);
        return list;
    }


    public static void main(String[] args) throws Exception {

    }

}
